<?php

declare(strict_types=1);

namespace app\index\logic\users;

use app\index\logic\BaseLogic;
use app\common\model\users\Users as UsersModel;
use app\common\service\third_party_api\WechatApiService;
use app\common\service\third_party_api\SMSService;
use app\common\service\Util;
use think\facade\Db;
use think\facade\Log;
use think\facade\Cache;

/**
 * 用户逻辑层
 * 处理用户相关的业务逻辑，解耦模型层
 */
class UsersLogic extends BaseLogic
{
    /**
     * 用户模型实例
     * @var UsersModel
     */
    protected $usersModel;

    /**
     * 当前用户ID
     * @var int|null
     */
    protected static $userId = null;

    /**
     * 当前用户信息
     * @var array|null
     */
    protected static $userInfo = null;

    public function __construct()
    {
        $this->usersModel = new UsersModel();
    }

    

    /**
     * 登录或注册一体化
     * 根据手机号和短信验证码，如果用户存在则登录，不存在则自动注册
     * @param string $mobile 手机号
     * @param string $smsCode 短信验证码
     * @return array|null 用户信息数组
     */
    public function loginOrRegister(string $mobile, string $smsCode): ?array
    {
        try {
            // 验证手机号格式
            if (!Util::validateMobile($mobile)) {
                Log::error('登录/注册失败：手机号格式不正确 - ' . $mobile);
                return null;
            }
            
            // 从缓存中获取短信验证码并验证
            $cachedSmsCode = Cache::get('sms_code:' . $mobile);
            if (empty($cachedSmsCode) || $cachedSmsCode !== $smsCode) {
                return null; // 验证码错误或过期
            }
            
            // 查询用户是否存在
            $userInfo = $this->usersModel->where('mobile', $mobile)->find();
            
            // 如果用户不存在，自动注册
            if (empty($userInfo)) {
                $username = '新注册用户' . substr($mobile, -6);
                $password = md5(time() . mt_rand(100000, 999999)); // 生成6位随机密码

                $userId = $this->usersModel->save([
                    'mobile' => $mobile,
                    'username' => $username,
                    'password' => $password,
                    'create_time' => time(),
                    'last_login_time' => time(),
                    'last_login_ip' => request()->ip(),
                    'need_authentication' => 1,
                    'status' => 1
                ]);

                if ($userId) {
                    Log::info('自动注册成功：用户ID - ' . $userId . '，手机号 - ' . $mobile);
                    $userInfo = $this->usersModel->where('id', $userId)->find();
                } else {
                    Log::error('自动注册失败：数据库保存失败 - ' . $mobile);
                    return null;
                }
            } else {
                // 更新用户最后登录信息
                $userInfo->last_login_time = time();
                $userInfo->last_login_ip = request()->ip();
                $userInfo->save();
                Log::info('登录成功：用户ID - ' . $userInfo['id'] . '，手机号 - ' . $mobile);
            }
            
            return $userInfo;
        } catch (\Exception $e) {
            Log::error('登录/注册异常：' . $e->getMessage() . ' - 手机号：' . $mobile);
            return null;
        }
    }

    /**
     * 生成用户token（可加解密的字符串）
     * @param int $userId 用户ID
     * @return string 生成的token
     */
    public function generateToken(int $userId): string
    {
        // 创建包含用户ID和时间戳的token数据
        $tokenData = [
            'user_id' => $userId,
            'timestamp' => time(),
            'expire' => time() + 7 * 24 * 3600 // 7天有效期
        ];

        // 将数据转换为JSON字符串
        $tokenJson = json_encode($tokenData);

        // 使用openssl进行加密（使用AES-256-CBC加密算法）
        $appKey = config('app.app_key', 'default_app_key_for_token'); // 从配置中获取应用密钥
        $salt = config('app.token_salt', 'default_token_salt'); // 从配置中获取盐值，可在.env文件中设置
        $key = hash('sha256', $appKey . $salt); // 结合应用密钥和盐值生成最终密钥
        $iv = substr(md5($key), 0, 16); // 生成初始化向量

        // 确保数据长度是16的倍数
        $pad = 16 - (strlen($tokenJson) % 16);
        $tokenJson .= str_repeat(chr($pad), $pad);

        // 加密数据
        $encrypted = openssl_encrypt($tokenJson, 'AES-256-CBC', $key, 0, $iv);

        // base64编码以确保安全传输
        $token = base64_encode($encrypted);

        return $token;
    }

    /**
     * 生成并发送短信验证码
     * @param string $mobile 手机号码
     * @return array [status: bool, message: string]
     */
    public function sendSmsCode(string $mobile): array
    {
        try {
            // 验证手机号格式
            if (!Util::validateMobile($mobile)) {
                Log::error('发送短信验证码失败：手机号格式不正确 - ' . $mobile);
                return ['status' => false, 'message' => '手机号格式不正确'];
            }

            // 检查是否频繁发送（60秒内只能发送一次）
            $lastSendTime = Cache::get('sms_last_send_time:' . $mobile);
            if ($lastSendTime && time() - $lastSendTime < 60) {
                Log::notice('发送短信验证码失败：发送过于频繁 - ' . $mobile);
                return ['status' => false, 'message' => '请勿频繁发送验证码，60秒后重试'];
            }

            // 生成6位随机验证码
            $code = mt_rand(100000, 999999);

            // 创建短信服务实例并发送验证码
            $smsService = new SMSService();
            $sendResult = $smsService->send($mobile, $code);

            if (!$sendResult) {
                Log::error('发送短信验证码失败：服务调用失败 - ' . $mobile);
                return ['status' => false, 'message' => '短信发送失败，请稍后重试'];
            }

            // 将验证码存入缓存，有效期5分钟
            Cache::set('sms_code:' . $mobile, $code, 300);

            // 记录最后发送时间
            Cache::set('sms_last_send_time:' . $mobile, time(), 60);

            Log::info('短信验证码发送成功 - 手机号：' . $mobile . '，验证码：' . $code);
            return ['status' => true, 'message' => '验证码已发送'];
        } catch (\Exception $e) {
            Log::error('发送短信验证码异常：' . $e->getMessage() . ' - 手机号：' . $mobile);
            return ['status' => false, 'message' => '系统异常，请稍后重试'];
        }
    }

    /**
     * 微信第三方登录
     * @param string $code 微信授权code
     * @return bool 登录结果
     */
    public function wechatLogin($code)
    {
        // 参数验证
        if (empty($code)) {
            throw new \Exception('授权code不能为空');
        }

        try {
            // 实例化微信API服务
            $wechatApiService = new WechatApiService();

            // 获取微信openid和session_key
            $rs = $wechatApiService->getOpenIdByCode($code);
            if (!$rs) {
                return false;
            }

            $openid = $rs['openid'];
            $sessionKey = $rs['session_key'];
            $nickname = isset($rs['nickName']) ? $rs['nickName'] : '';
            $avatar = isset($rs['avatarUrl']) ? $rs['avatarUrl'] : '';

            // 查询用户是否已存在
            $userInfo = $this->usersModel->getUserByOpenid($openid);

            // 如果用户不存在，创建新用户
            if (empty($userInfo)) {
                $this->usersModel->save([
                    'openid' => $openid,
                    'create_time' => time(),
                    'last_login_time' => time(),
                    'nickname' => '微信用户' . $nickname,
                    'avatar' => $avatar
                ]);
                $userId = $this->usersModel->getLastInsID();

                $userInfo = $this->usersModel->where('id', $userId)->find();
            } else {
                // 更新用户登录时间
                $this->usersModel->where('id', $userInfo['id'])->update([
                    'last_login_time' => time(),
                    'last_login_ip' => request()->ip()
                ]);
            }

            // 设置用户信息
            self::$userId = $userInfo['id'];
            self::$userInfo = $userInfo;

            // 存储session_key到缓存
            Cache::set('wechat_session_key_' . $userInfo['id'], $sessionKey, 86400);

            return true;
        } catch (\Exception $e) {
            Log::error('微信登录异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 实名认证
     * @param string $name 姓名
     * @param string $idcard 身份证号
     * @return array 返回认证结果信息数组
     */
    public function realnameAuthentication(string $name, string $idcard)
    {
        // 判断一个月内已认证成功的身份证不用重复认证
        // 使用app_config表存储实名认证记录，通过name和id_num的组合来查找
        $succeedData = Db::name('realname_authentication_log')
            ->where('uni_code', md5($name . $idcard)) // 使用姓名+身份证号的md5值作为唯一标识
            ->where('create_time', '>', time() - 30 * 86400)
            ->find();

        if (!empty($succeedData)) {
            // 已存在近期成功认证记录，直接返回成功
            return [
                'status' => 1,
                'message' => '实名认证成功'
            ];
        }

        // 调用第三方实名认证API - 使用Util工具类的sendPostRequest方法
        $host = env('TC_REAL_NAME_URL'); // 从配置文件中获取api url
        $appcode = env('TC_REAL_NAME_KEY'); // 从配置文件中获取appcode
        $headers = ["Authorization:APPCODE " . $appcode];
        $querys = "idcard=" . urlencode($idcard) . "&name=" . urlencode($name);
        $url = $host . "?" . $querys;

        try {
            $result = Util::sendPostRequest($url, [], $headers);
        } catch (\Exception $e) {
            // API调用失败
            return [
                'status' => 0,
                'message' => '实名认证服务异常，请稍后再试: ' . $e->getMessage()
            ];
        }

        if ($result['code'] == 0) {
            if ($result['result']['res'] == 1) {
                // 认证成功，记录日志到app_config表
                Db::name('realname_authentication_log')->insert([
                    'uni_code' => md5($name . $idcard), // 使用姓名+身份证号的md5值作为唯一标识
                    'create_time' => time()
                ]);

                return [
                    'status' => 1,
                    'message' => '实名认证成功'
                ];
            } else {
                // 认证失败，根据错误码返回不同信息
                switch ($result['result']['res']) {
                    case 2:
                        $message = '姓名不正确，请重新填写';
                        break;
                    case 3:
                        $message = '身份证号无记录，请重新填写';
                        break;
                    default:
                        $message = '身份证号码不正确，请重新填写';
                        break;
                }

                return [
                    'status' => 0,
                    'message' => $message
                ];
            }
        } else {
            // API调用失败
            return [
                'status' => 0,
                'message' => '实名认证服务暂时不可用，请稍后再试'
            ];
        }
    }

    /**
     * 更新用户微信信息
     * @param int $userId 用户ID
     * @param array $wechatInfo 微信信息
     * @return bool 更新结果
     */
    public function updateWechatInfo(int $userId, array $wechatInfo)
    {
        $userId = intval($userId);
        if ($userId <= 0 || empty($wechatInfo)) {
            return false;
        }

        return $this->usersModel->where('id', $userId)->update($wechatInfo);
    }

    /**
     * 更新用户个人信息
     * @param int $userId 用户ID
     * @param array $param 更新参数
     * @return array 更新结果
     */
    public function updateProfile(int $userId, array $param)
    {
        $userId = intval($userId);
        if ($userId <= 0 || empty($param)) {
            return [
                'status' => 0,
                'message' => '参数错误'
            ];
        }

        $result = $this->usersModel->where('id', $userId)->update($param);
        if (!$result) {
            return [
                'status' => 0,
                'message' => '更新失败'
            ];
        }

        return [
            'status' => 1,
            'message' => '更新成功'
        ];
    }

    /**
     * 设置用户ID
     * @param int $userId 用户ID
     */
    public static function setUserId($userId)
    {
        self::$userId = $userId;
    }

    /**
     * 设置用户信息
     * @param array $userInfo 用户信息
     */
    public static function setUserInfo($userInfo)
    {
        self::$userInfo = $userInfo;
    }

    /**
     * 获取当前用户ID
     * @return int|null
     */
    public static function getUserId()
    {
        return self::$userId;
    }

    /**
     * 获取当前用户信息
     * @return array|null
     */
    public static function getUserInfo()
    {
        return self::$userInfo;
    }

    /**
     * 通过token获取用户信息
     * @param string $token 用户token
     * @return array|null 用户信息数组或null
     */
    public static function getUserInfoByToken(string $token)
    {
        if (empty($token)) {
            return null;
        }

        try {
            // base64解码
            $encrypted = base64_decode($token);

            if (empty($encrypted)) {
                return null;
            }

            // 使用openssl进行解密
            $appKey = config('app.app_key', 'default_app_key_for_token'); // 从配置中获取应用密钥
            $salt = config('app.token_salt', 'default_token_salt'); // 从配置中获取盐值，与加密时使用相同的值
            $key = hash('sha256', $appKey . $salt); // 结合应用密钥和盐值生成最终密钥
            $iv = substr(md5($key), 0, 16); // 与加密时使用相同的初始化向量

            // 解密数据
            $tokenJson = openssl_decrypt($encrypted, 'AES-256-CBC', $key, 0, $iv);

            if (empty($tokenJson)) {
                return null;
            }

            // 去除填充
            $pad = ord(substr($tokenJson, -1));
            $tokenJson = substr($tokenJson, 0, -$pad);

            // 解析JSON数据
            $tokenData = json_decode($tokenJson, true);

            if (empty($tokenData) || !isset($tokenData['user_id']) || !isset($tokenData['expire'])) {
                return null;
            }

            // 检查token是否过期
            if (time() > $tokenData['expire']) {
                return null;
            }

            // 创建UsersLogic实例
            $usersLogic = new self();

            // 根据用户ID获取用户信息
            $userInfo = $usersLogic->usersModel->where('id', $tokenData['user_id'])->find();

            return $userInfo;
        } catch (\Exception $e) {
            Log::error('Token解密失败: ' . $e->getMessage());
            return null;
        }
    }
}
